﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Windows.Forms;

namespace MathService.Functions.Plotter.GraphComponents
{
    public class Plotter : Graph
    {
        #region Delegates

        public delegate void PlotterEventHandler(object sender, PlotterEventArgs e);

        #endregion

        #region PlotterState enum

        public enum PlotterState { Reset, Running, Stopped }

        #endregion

        #region Поля

        private readonly AxisLine axisLineXandY;
        private readonly int buttonHeight;
        private readonly int buttonWidth;
        private readonly ChannelCollection channelCollection;
        private readonly Gridline gridline;
        private int activeChannelIndex;
        private Button buttonNextChannel;
        private Button buttonPrevChannel;
        private Button buttonUpperYMinus;
        private Button buttonUpperYPlus;
        private bool compressedMode;
        private PlotterState currentState;
        private int graphMarginBottom = 20;
        private int graphMarginLeft = 50;
        private int graphMarginRight = 20;
        private int graphMarginTop = 20;
        private int initialPlotRate;
        private int leftDisplayLimit;
        private Point mouseHoverCoordinates;
        private int plotRate = 300;
        private HScrollBar plotterHScrollBar;
        //private TimeSpan plotterPenPosition;
        private int pointsToRemove;
        private int rightDisplayLimit;
        private int savedLeftDisplayLimit;
        private int savedPointsToRemove;
        private TimeSpan savedXRange;
        private int stoppedLeftDisplayLimit;
        private TimeAxisStyle timeDisplayStyle = TimeAxisStyle.Smart;
        private int totalPointsToRemove;
        private int totalTimeElapsed;
        private TimeSpan xRange = new TimeSpan(0, 0, 9);

        #endregion

        public event PlotterEventHandler PlotterStateChanged;

        [Browsable(false)]
        public Channel ActiveChannel { get { return channelCollection[activeChannelIndex]; } }

        [Browsable(false)]
        public int ActiveChannelIndex { get { return activeChannelIndex; } }

        [Browsable(false)]
        public ChannelCollection Channels { get { return channelCollection; } }

        [Browsable(false)]
        public bool CompressedMode
        {
            get { return compressedMode; }
            set
            {
                if(currentState != PlotterState.Stopped)
                {
                    compressedMode = false;
                    xRange = savedXRange;
                }
                else if(compressedMode != value)
                {
                    compressedMode = value;
                    if(compressedMode)
                    {
                        savedXRange = xRange;
                        savedLeftDisplayLimit = leftDisplayLimit;
                        savedPointsToRemove = pointsToRemove;
                        xRange = new TimeSpan(totalTimeElapsed * 10000);
                        leftDisplayLimit = 0;
                        pointsToRemove = 0;
                    }
                    else
                    {
                        xRange = savedXRange;
                        leftDisplayLimit = savedLeftDisplayLimit;
                        pointsToRemove = savedPointsToRemove;
                    }
                    plotterHScrollBar.Visible = !compressedMode;
                    RefreshDisplay();
                }
            }
        }

        [Browsable(false)]
        public PlotterState CurrentState { get { return currentState; } }

        [Category("Appearance"), Description("Ширина нижнего края графика"), Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int GraphMarginBottom
        {
            get { return graphMarginBottom; }
            set
            {
                if(value < 0)
                    throw new ArgumentException("Неверное значение свойства. " +
                                                "Ширина крайя графика не может быть отрицательной.");
                graphMarginBottom = value;
                RefreshDisplay();
            }
        }

        [Description("Ширина края графика слева"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Browsable(true),
         Category("Appearance")]
        public int GraphMarginLeft
        {
            get { return graphMarginLeft; }
            set
            {
                if(value < 0)
                    throw new ArgumentException("Invalid property value. Margin cannot be negative.");
                graphMarginLeft = value;
                RefreshDisplay();
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Category("Appearance"),
         Description("Ширина края графика справа"), Browsable(true)]
        public int GraphMarginRight
        {
            get { return graphMarginRight; }
            set
            {
                if(value < 0)
                    throw new ArgumentException("Invalid property value. Margin cannot be negative.");
                graphMarginRight = value;
                RefreshDisplay();
            }
        }

        [Description("Ширина графика сверху"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Browsable(true),
         Category("Appearance")]
        public int GraphMarginTop
        {
            get { return graphMarginTop; }
            set
            {
                if(value < 0)
                    throw new ArgumentException("Invalid property value. Margin cannot be negative.");
                graphMarginTop = value;
                RefreshDisplay();
            }
        }

        public int PlotRate
        {
            get { return plotRate; }
            set
            {
                plotRate = value;
                if(plotRate > initialPlotRate)
                    initialPlotRate = plotRate;
                foreach(Channel channel in Channels)
                    channel.PlotRate = plotRate;
            }
        }

        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Category("Appearance"), Description("Style in which the values on the time axis (X axis) is to be shown")]
        public TimeAxisStyle TimeDisplayStyle { get { return timeDisplayStyle; } set { timeDisplayStyle = value; } }

        [Browsable(false)]
        public int TotalTimeElapsed { get { return totalTimeElapsed; } set { totalTimeElapsed = value; } }

        public TimeSpan XRange { get { return xRange; } set { xRange = value; } }

        [Category("Appearance"), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Browsable(false), Description("Color of the Y axis"), Obsolete("This property is not valid for the bar graph.")
        ]
        public override Color YAxisColor { get { return base.YAxisColor; } set { base.YAxisColor = value; } }

        public Plotter()
        {
            InitializeComponent();
            channelCollection = new ChannelCollection();
            //Channels.Add(new Channel(0f, 100f, "Voltage", true, Color.Blue));
            //Channels.Add(new Channel(0f, 5f, "Current", true, Color.Red));
            Channels.Add(new Channel(0, 100, "2", false, Color.Green));
            Channels.Add(new Channel(0, 100, "3", false, Color.Purple));
            gridline = new Gridline(this);
            axisLineXandY = new AxisLine(this);
            SetStyle(ControlStyles.DoubleBuffer
                     | ControlStyles.AllPaintingInWmPaint
                     | ControlStyles.UserPaint, true);
            UpdateStyles();
            PlotRate = 300;
            initialPlotRate = PlotRate;
            GraphArea =
                        new Rectangle(ClientRectangle.Left + graphMarginLeft,
                                      ClientRectangle.Top + graphMarginTop,
                                      ClientRectangle.Width - graphMarginRight - graphMarginLeft,
                                      ClientRectangle.Height - graphMarginBottom - graphMarginTop);
            //plotterPenPosition = new TimeSpan((long)(xRange.Duration().Ticks * 0.9));
            var num = (int)(xRange.Duration().Ticks / 10000);
            plotterHScrollBar.Maximum = num / PlotRate;
            plotterHScrollBar.Value = num / PlotRate;
            plotterHScrollBar.Visible = false;
            rightDisplayLimit = num - leftDisplayLimit;
            savedXRange = xRange;
            ValueFormat = "{0:F}";
            buttonWidth = buttonPrevChannel.Width;
            buttonHeight = buttonPrevChannel.Height;
        }

        private void buttonNextChannel_Click(object sender, EventArgs e) { NextChannel(); }

        private void buttonPrevChannel_Click(object sender, EventArgs e) { PreviousChannel(); }

        private void buttonUpperYMinus_Click(object sender, EventArgs e)
        {
            var num = (ActiveChannel.MaximumValue - ActiveChannel.MinimumValue) / 20f;
            var activeChannel = ActiveChannel;
            activeChannel.MaximumValue -= num;
            var channel2 = ActiveChannel;
            channel2.MinimumValue -= num;
            if(currentState != PlotterState.Running)
                RefreshDisplay();
        }

        private void buttonUpperYPlus_Click(object sender, EventArgs e)
        {
            var num = (ActiveChannel.MaximumValue - ActiveChannel.MinimumValue) / 20f;
            var activeChannel = ActiveChannel;
            activeChannel.MaximumValue += num;
            var channel2 = ActiveChannel;
            channel2.MinimumValue += num;
            if(currentState != PlotterState.Running)
                RefreshDisplay();
        }

        private void CalculateGraphArea()
        {
            GraphArea = new Rectangle(ClientRectangle.Left + graphMarginLeft,
                                      ClientRectangle.Top + graphMarginTop,
                                      ClientRectangle.Width - graphMarginRight - graphMarginLeft,
                                      ClientRectangle.Height - graphMarginBottom - graphMarginTop);
        }

        //protected override void Dispose(bool disposing) { base.Dispose(disposing); }

        public override void Draw(Graphics graphics)
        {
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            CalculateGraphArea();
            if(GraphArea.Width == 0 || GraphArea.Height == 0) return;
            graphics.SetClip(GraphArea);
            gridline.Draw(graphics);
            base.YAxisColor = ActiveChannel.ChannelColor;
            axisLineXandY.Draw(graphics);
            DrawYAxisValues(graphics);
            DrawXAxisValues(graphics);
            DrawChannelChangingButtons();
            DrawLimitChangingButtons();
            graphics.SetClip(GraphArea);
            if(currentState == PlotterState.Reset) return;
            DrawCrossHair(graphics);
            DrawXYText(graphics);
            ActiveChannel.ChannelCursor.GraphArea = GraphArea;
            ActiveChannel.ChannelCursor.Draw(graphics);
            var num = (int)(xRange.Duration().Ticks / 10000);
            rightDisplayLimit = leftDisplayLimit + num;
            if((TotalTimeElapsed > rightDisplayLimit) && (currentState == PlotterState.Running))
            {
                plotterHScrollBar.Maximum = pointsToRemove;
                plotterHScrollBar.Value = pointsToRemove;
                pointsToRemove++;
                var tf = (PointF)ActiveChannel.Points[pointsToRemove];
                var num2 = ((int)tf.X) - leftDisplayLimit;
                if(num2 > plotRate)
                    leftDisplayLimit = (int)tf.X;
                else
                    leftDisplayLimit += plotRate;
            }
            var flag = false;
            for(var i = 0; i < Channels.Count; i++)
            {
                var channel = Channels[i];
                if(!channel.Enabled) continue;
                if(!flag && TotalTimeElapsed > rightDisplayLimit
                    && currentState == PlotterState.Running)
                {
                    plotterHScrollBar.Maximum = pointsToRemove;
                    plotterHScrollBar.Value = pointsToRemove;
                    pointsToRemove++;
                    var tf2 = (PointF)channel.Points[pointsToRemove];
                    var num4 = ((int)tf2.X) - leftDisplayLimit;
                    if(num4 > plotRate)
                        leftDisplayLimit = (int)tf2.X;
                    else
                        leftDisplayLimit += plotRate;
                    flag = true;
                }
                var list = new ArrayList();
                Trace.WriteLine(channel.Points.Count);
                TotalTimeElapsed = channel.TotalTimeElapsed;
                for(var j = 0; j < (channel.Points.Count - pointsToRemove); j++)
                {
                    var tf3 = (PointF)channel.Points[j + pointsToRemove];
                    var point = GetPixelFromValue(channel, (int)tf3.X, tf3.Y);
                    list.Add(point);
                }
                if(list.Count < 2) continue;
                var points = new Point[list.Count];
                for(var k = 0; k < list.Count; k++)
                {
                    points[k] = (Point)list[k];
                }
                graphics.SetClip(GraphArea);
                graphics.DrawLines(
                                   i == activeChannelIndex
                                               ? new Pen(channel.ChannelColor, 1.75f)
                                               : new Pen(channel.ChannelColor, 1.5f), points);
            }
        }

        private void DrawChannelChangingButtons()
        {
            buttonPrevChannel.Left = GraphArea.Left + (buttonWidth / 2);
            buttonPrevChannel.Top = GraphArea.Top + (buttonHeight / 2);
            buttonNextChannel.Left = buttonPrevChannel.Right + 1;
            buttonNextChannel.Top = GraphArea.Top + (buttonHeight / 2);
            buttonPrevChannel.ForeColor = Channels[activeChannelIndex].ChannelColor;
            buttonNextChannel.ForeColor = Channels[activeChannelIndex].ChannelColor;
            buttonPrevChannel.BackColor = GraphAreaColor;
            buttonNextChannel.BackColor = GraphAreaColor;
        }

        private void DrawCrossHair(Graphics graphics)
        {
            if(currentState == PlotterState.Stopped
                && mouseHoverCoordinates.X >= GraphArea.Left
                    && mouseHoverCoordinates.X <= GraphArea.Right
                && mouseHoverCoordinates.Y >= GraphArea.Top
                    && mouseHoverCoordinates.Y <= GraphArea.Bottom)
            {
                var pen = new Pen(GridlineColor);
                graphics.DrawLine(pen, mouseHoverCoordinates.X, GraphArea.Top, mouseHoverCoordinates.X,
                                  GraphArea.Bottom);
                pen.Dispose();
            }
        }

        private void DrawLimitChangingButtons()
        {
            var channelColor = Channels[activeChannelIndex].ChannelColor;
            buttonUpperYPlus.Left = GraphArea.Left + buttonWidth / 2;
            buttonUpperYPlus.Top = buttonPrevChannel.Bottom + 2;
            buttonUpperYMinus.Left = buttonUpperYPlus.Right + 1;
            buttonUpperYMinus.Top = buttonPrevChannel.Bottom + 2;
            buttonUpperYPlus.ForeColor = channelColor;
            buttonUpperYMinus.ForeColor = channelColor;
            buttonUpperYPlus.BackColor = GraphAreaColor;
            buttonUpperYMinus.BackColor = GraphAreaColor;
        }

        private void DrawXAxisValues(Graphics graphics)
        {
            graphics.SetClip(ClientRectangle);
            var format = new StringFormat
                             {
                                 Trimming = StringTrimming.Character,
                                 FormatFlags = StringFormatFlags.NoWrap,
                                 Alignment = StringAlignment.Center,
                                 LineAlignment = StringAlignment.Center
                             };
            Brush brush = new SolidBrush(XAxisColor);
            float left = GraphArea.Left;
            float num2 = GraphArea.Width / GraduationsX;
            var num3 = (int)(xRange.Duration().Ticks / 0x2710);
            float num4 = num3 / GraduationsX;
            for(var i = 0; i <= GraduationsX; i++)
            {
                var num6 = leftDisplayLimit + (num4 * i);
                var formatForTime = GetFormatForTime((int)num6);
                var ef = graphics.MeasureString(formatForTime, Font, (int)num2);
                var layoutRectangle =
                    new RectangleF(left - ef.Width / 2f, GraphArea.Bottom + 4, ef.Width, Font.Height);
                graphics.DrawString(formatForTime, Font, brush, layoutRectangle, format);
                left += num2;
            }
        }

        private void DrawXYText(Graphics graphics)
        {
            if(currentState == PlotterState.Stopped
                && mouseHoverCoordinates.X >= GraphArea.Left
                    && mouseHoverCoordinates.X <= GraphArea.Right
                && mouseHoverCoordinates.Y >= GraphArea.Top
                    && mouseHoverCoordinates.Y <= GraphArea.Bottom)
            {
                var channel = Channels[activeChannelIndex];
                var tf = GetValueFromPixel(channel, mouseHoverCoordinates.X, mouseHoverCoordinates.Y);
                var timeInMilisecond = leftDisplayLimit + (int)tf.X;
                var num2 = timeInMilisecond % plotRate;
                timeInMilisecond -= num2;
                var key = timeInMilisecond / plotRate;
                var naN = float.NaN;
                string s;
                if(channel.Points.ContainsKey(key))
                {
                    var tf2 = (PointF)channel.Points[key];
                    naN = tf2.Y;
                }
                if(float.IsNaN(naN))
                    s = GetFormatForTime(timeInMilisecond) + ", -";
                else
                {
                    var str2 = string.Format(CultureInfo.InstalledUICulture,
                        ValueFormat.Length != 0 ? ValueFormat : "{0:F}",
                        new object[] { naN });
                    s = GetFormatForTime(timeInMilisecond) + ", " + str2;
                }
                var format = new StringFormat
                                 {
                                     Trimming = StringTrimming.Character,
                                     FormatFlags = StringFormatFlags.NoWrap,
                                     Alignment = StringAlignment.Center,
                                     LineAlignment = StringAlignment.Center
                                 };
                var stringSize = graphics.MeasureString(" " + s + " ", Font, GraphArea.Width, format);
                Brush brush = new SolidBrush(Color.FromArgb(50, channel.ChannelColor));
                var coordinateTextRect = GetCoordinateTextRect(stringSize);
                var pen = new Pen(GridlineColor);
                Brush brush2 = new SolidBrush(channel.ChannelColor);
                graphics.DrawRectangle(pen, coordinateTextRect);
                graphics.FillRectangle(brush, coordinateTextRect);
                graphics.DrawString(s, Font, brush2, coordinateTextRect, format);
                brush2.Dispose();
                pen.Dispose();
            }
        }

        private void DrawYAxisValues(Graphics graphics)
        {
            graphics.SetClip(ClientRectangle);
            var format = new StringFormat
                             {
                                 Trimming = StringTrimming.Character,
                                 FormatFlags = StringFormatFlags.NoWrap,
                                 Alignment = StringAlignment.Far,
                                 LineAlignment = StringAlignment.Center
                             };
            Brush brush = new SolidBrush(ActiveChannel.ChannelColor);
            float y = GraphArea.Top - (Font.Height / 2);
            float num2 = GraphArea.Height / GraduationsY;
            float num3 = 0f;
            float num4 = (ActiveChannel.MaximumValue - ActiveChannel.MinimumValue) / (base.GraduationsY);
            for(int i = base.GraduationsY; i >= 0; i--)
            {
                var layoutRectangle = new RectangleF(base.ClientRectangle.Left, y, (GraphMarginLeft - (Font.Height / 2)),
                                                     Font.Height);
                float num6 = ActiveChannel.MaximumValue - (num4 * num3);
                num3++;
                string s = "";
                if(base.ValueFormat.Length != 0)
                {
                    s = string.Format(CultureInfo.CurrentUICulture, base.ValueFormat, new object[] { num6 });
                }
                else
                {
                    s = string.Format(CultureInfo.CurrentUICulture, "{0:F}", new object[] { num6 });
                }
                graphics.DrawString(s, Font, brush, layoutRectangle, format);
                y += num2;
            }
        }

        private Rectangle GetCoordinateTextRect(SizeF stringSize)
        {
            int x = 0;
            if(((mouseHoverCoordinates.X + stringSize.Width) + 2f) > base.GraphArea.Right)
            {
                x = (mouseHoverCoordinates.X - ((int)(stringSize.Width + 0.5))) - 2;
            }
            else
            {
                x = mouseHoverCoordinates.X + 2;
            }
            int height = 2 * Font.Height;
            return new Rectangle(x, (base.GraphArea.Bottom - height) - 2, (int)(stringSize.Width + 0.5), height);
        }

        private string GetFormatForTime(int timeInMilisecond)
        {
            string str = "";
            switch(timeDisplayStyle)
            {
                case TimeAxisStyle.Millisecond:
                    return string.Format(CultureInfo.CurrentUICulture, "{0:G}", new object[] { timeInMilisecond });

                case TimeAxisStyle.MillisecondWithUnitDisplay:
                    return string.Format(CultureInfo.CurrentUICulture, "{0:G}ms", new object[] { timeInMilisecond });

                case TimeAxisStyle.Second:
                    return string.Format(CultureInfo.CurrentUICulture, "{0:D2}:{1:D3}",
                                         new object[] { timeInMilisecond / 0x3e8, timeInMilisecond % 0x3e8 });

                case TimeAxisStyle.SecondWithUnitDisplay:
                    return string.Format(CultureInfo.CurrentUICulture, "{0:D2}:{1:D3}s",
                                         new object[] { timeInMilisecond / 0x3e8, timeInMilisecond % 0x3e8 });

                case TimeAxisStyle.Smart:
                    if(plotRate >= 0x3e8)
                    {
                        if(timeInMilisecond < 0xea60)
                        {
                            int num12 = timeInMilisecond / 0x3e8;
                            return string.Format(CultureInfo.CurrentUICulture, "{0:G}", new object[] { num12 });
                        }
                        if((timeInMilisecond >= 0xea60) && (timeInMilisecond < 0x36ee80))
                        {
                            int num13 = timeInMilisecond / 0x3e8;
                            int num14 = num13 % 60;
                            num13 /= 60;
                            int num15 = num13;
                            return string.Format(CultureInfo.CurrentUICulture, "{0}:{1:D2}", new object[] { num15, num14 });
                        }
                        if(timeInMilisecond >= 0x36ee80)
                        {
                            int num16 = timeInMilisecond / 0x3e8;
                            int num17 = num16 % 60;
                            num16 /= 60;
                            int num18 = num16 % 60;
                            num16 /= 60;
                            int num19 = num16;
                            str = string.Format(CultureInfo.CurrentUICulture, "{0}:{1:D2}:{2:D2}",
                                                new object[] { num19, num18, num17 });
                        }
                        return str;
                    }
                    new TimeSpan(timeInMilisecond * 0x2710);
                    if(timeInMilisecond >= 0x2710)
                    {
                        if((timeInMilisecond >= 0x2710) && (timeInMilisecond < 0xea60))
                        {
                            int num = timeInMilisecond % 0x3e8;
                            int num2 = timeInMilisecond / 0x3e8;
                            return string.Format(CultureInfo.CurrentUICulture, "{0:D2}:{1:D3}", new object[] { num2, num });
                        }
                        if((timeInMilisecond >= 0xea60) && (timeInMilisecond < 0x36ee80))
                        {
                            int num3 = timeInMilisecond;
                            int num4 = num3 % 0x3e8;
                            num3 /= 0x3e8;
                            int num5 = num3 % 60;
                            num3 /= 60;
                            int num6 = num3;
                            return string.Format(CultureInfo.CurrentUICulture, "{0}:{1:D2}:{2:D3}",
                                                 new object[] { num6, num5, num4 });
                        }
                        if(timeInMilisecond >= 0x36ee80)
                        {
                            int num7 = timeInMilisecond;
                            int num8 = num7 % 0x3e8;
                            num7 /= 0x3e8;
                            int num9 = num7 % 60;
                            num7 /= 60;
                            int num10 = num7 % 60;
                            num7 /= 60;
                            int num11 = num7;
                            str = string.Format(CultureInfo.CurrentUICulture, "{0}:{1:D2}:{2:D2}:{3:D3}",
                                                new object[] { num11, num10, num9, num8 });
                        }
                        return str;
                    }
                    return string.Format(CultureInfo.CurrentUICulture, "{0:G}", new object[] { timeInMilisecond });
            }
            return str;
        }

        private Point GetPixelFromValue(Channel channel, int XinValue, float YinValue)
        {
            float num = channel.MaximumValue - channel.MinimumValue;
            float num2 = (YinValue - channel.MinimumValue) / num;
            int y = base.GraphArea.Bottom - ((int)(num2 * base.GraphArea.Height));
            int num4 = XinValue;
            num4 -= leftDisplayLimit;
            var num5 = (int)(xRange.Duration().Ticks / 0x2710);
            float num6 = (num4) / ((float)num5);
            return new Point(base.GraphArea.Left + ((int)(num6 * base.GraphArea.Width)), y);
        }

        private PointF GetValueFromPixel(Channel channel, int XInPixel, int YInPixel)
        {
            float num = ((base.GraphArea.Bottom - YInPixel)) / ((float)base.GraphArea.Height);
            float num2 = channel.MaximumValue - channel.MinimumValue;
            float y = channel.MinimumValue + (num * num2);
            var num4 = (int)(xRange.Duration().Ticks / 0x2710);
            float num5 = ((XInPixel - base.GraphArea.Left)) / ((float)base.GraphArea.Width);
            return new PointF(num5 * num4, y);
        }

        private void InitializeComponent()
        {
            plotterHScrollBar = new HScrollBar();
            buttonPrevChannel = new Button();
            buttonNextChannel = new Button();
            buttonUpperYPlus = new Button();
            buttonUpperYMinus = new Button();
            base.SuspendLayout();
            plotterHScrollBar.Dock = DockStyle.Bottom;
            plotterHScrollBar.Location = new Point(0, 0xef);
            plotterHScrollBar.Name = "plotterHScrollBar";
            plotterHScrollBar.Size = new Size(0x158, 0x11);
            plotterHScrollBar.TabIndex = 1;
            plotterHScrollBar.Scroll += plotterHScrollBar_Scroll;
            buttonPrevChannel.BackColor = SystemColors.Control;
            buttonPrevChannel.FlatStyle = FlatStyle.Flat;
            buttonPrevChannel.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Bold, GraphicsUnit.Point, 0);
            buttonPrevChannel.Location = new Point(0x18, 40);
            buttonPrevChannel.Name = "buttonPrevChannel";
            buttonPrevChannel.Size = new Size(0x10, 0x12);
            buttonPrevChannel.TabIndex = 2;
            buttonPrevChannel.Text = "<";
            buttonPrevChannel.Click += buttonPrevChannel_Click;
            buttonNextChannel.BackColor = SystemColors.Control;
            buttonNextChannel.FlatStyle = FlatStyle.Flat;
            buttonNextChannel.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Bold, GraphicsUnit.Point, 0);
            buttonNextChannel.Location = new Point(40, 40);
            buttonNextChannel.Name = "buttonNextChannel";
            buttonNextChannel.Size = new Size(0x10, 0x12);
            buttonNextChannel.TabIndex = 3;
            buttonNextChannel.Text = ">";
            buttonNextChannel.Click += buttonNextChannel_Click;
            buttonUpperYPlus.BackColor = SystemColors.Control;
            buttonUpperYPlus.FlatStyle = FlatStyle.Flat;
            buttonUpperYPlus.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Bold, GraphicsUnit.Point, 0);
            buttonUpperYPlus.Location = new Point(0x18, 0x40);
            buttonUpperYPlus.Name = "buttonUpperYPlus";
            buttonUpperYPlus.Size = new Size(0x10, 0x12);
            buttonUpperYPlus.TabIndex = 4;
            buttonUpperYPlus.Text = "+";
            buttonUpperYPlus.Click += buttonUpperYPlus_Click;
            buttonUpperYMinus.BackColor = SystemColors.Control;
            buttonUpperYMinus.FlatStyle = FlatStyle.Flat;
            buttonUpperYMinus.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Bold, GraphicsUnit.Point, 0);
            buttonUpperYMinus.Location = new Point(40, 0x40);
            buttonUpperYMinus.Name = "buttonUpperYMinus";
            buttonUpperYMinus.Size = new Size(0x10, 0x12);
            buttonUpperYMinus.TabIndex = 5;
            buttonUpperYMinus.Text = "-";
            buttonUpperYMinus.Click += buttonUpperYMinus_Click;
            base.Controls.Add(buttonUpperYMinus);
            base.Controls.Add(buttonUpperYPlus);
            base.Controls.Add(buttonNextChannel);
            base.Controls.Add(buttonPrevChannel);
            base.Controls.Add(plotterHScrollBar);
            base.Name = "Plotter";
            base.Size = new Size(0x158, 0x100);
            base.MouseMove += Plotter_MouseMove;
            base.ResumeLayout(false);
        }

        public void LoadFromFile(string fileName) { }

        public void NextChannel()
        {
            activeChannelIndex++;
            if(activeChannelIndex == Channels.Count)
            {
                activeChannelIndex = 0;
            }
            if(currentState != PlotterState.Running)
            {
                base.RefreshDisplay();
            }
            if(PlotterStateChanged != null)
            {
                PlotterStateChanged(this, new PlotterEventArgs(this));
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if(base.Visible)
            {
                Graphics graphics = e.Graphics;
                try
                {
                    Draw(graphics);
                }
                catch(NullReferenceException exception)
                {
                    Trace.WriteLine(exception);
                }
                base.OnPaint(e);
            }
        }

        private void Plotter_MouseMove(object sender, MouseEventArgs e)
        {
            if(currentState == PlotterState.Stopped)
            {
                mouseHoverCoordinates.X = e.X;
                mouseHoverCoordinates.Y = e.Y;
                base.RefreshDisplay();
            }
        }

        private void plotterHScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            pointsToRemove = e.NewValue;
            leftDisplayLimit = pointsToRemove * initialPlotRate;
            base.RefreshDisplay();
        }

        public void PreviousChannel()
        {
            activeChannelIndex--;
            if(activeChannelIndex < 0)
            {
                activeChannelIndex = Channels.Count - 1;
            }
            if(currentState != PlotterState.Running)
            {
                base.RefreshDisplay();
            }
            if(PlotterStateChanged != null)
            {
                PlotterStateChanged(this, new PlotterEventArgs(this));
            }
        }

        public void Reset()
        {
            if(currentState == PlotterState.Running)
            {
                Stop();
            }
            CompressedMode = false;
            currentState = PlotterState.Reset;
            leftDisplayLimit = 0;
            savedLeftDisplayLimit = 0;
            totalPointsToRemove = 0;
            pointsToRemove = 0;
            stoppedLeftDisplayLimit = 0;
            var num = (int)(xRange.Duration().Ticks / 0x2710);
            plotterHScrollBar.Visible = false;
            plotterHScrollBar.Maximum = num / initialPlotRate;
            plotterHScrollBar.Value = plotterHScrollBar.Maximum;
            TotalTimeElapsed = 0;
            foreach(Channel channel in Channels)
            {
                channel.CursorOffset = 0f;
                channel.Points.Clear();
                channel.TotalTimeElapsed = 0;
            }
            base.RefreshDisplay();
        }

        public void SaveToFile(string fileName) { }

        public void Start()
        {
            if(currentState != PlotterState.Running)
            {
                if(CompressedMode)
                {
                    CompressedMode = false;
                }
                currentState = PlotterState.Running;
                plotterHScrollBar.Visible = false;
                pointsToRemove = totalPointsToRemove;
                leftDisplayLimit = stoppedLeftDisplayLimit;
            }
        }

        public void Stop()
        {
            currentState = PlotterState.Stopped;
            if(pointsToRemove != 0)
            {
                stoppedLeftDisplayLimit = leftDisplayLimit;
                plotterHScrollBar.Visible = true;
                plotterHScrollBar.Maximum = pointsToRemove + plotterHScrollBar.LargeChange;
                plotterHScrollBar.Value = 0;
                totalPointsToRemove = pointsToRemove - 1;
                base.RefreshDisplay();
            }
        }

        public void UpdateDisplay() { base.RefreshDisplay(); }
    }
}
